package multiThread;

/**
 * @projectName: java-sample
 * @description:
 * @author: Adam
 * @create: 2020-01-07 10:26
 **/


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 等待/通知机制，是指一个线程A调用了对象O的wait()方法进入等待状态，而另一个线程B调用了对象O的notify()或notiryAll()方法，线程A收到通知后从对象O的wait()方法返回，
 * 进而执行后续操作。上述两个线程通过对象O来完成交互，而对象上的wait()和 notify/notifyAll() 的关系就如同开关信号一样，用来完成等待方和通知方直接的交互工作。
 */
public class ThreadNotity {

    private static boolean flag = true;
    private static Object lock = new Object();

    public static void main(String[] args) throws Exception{

        Thread waitThread = new Thread(new Wait(),"Wait Thread");
        waitThread.start();
        TimeUnit.SECONDS.sleep(1);
        Thread notifyThread = new Thread(new Notify(),"Notify Thread");
        notifyThread.start();
    }

    static class Wait implements Runnable{
        @Override
        public void run() {
            //同步代码块,加锁，拥有lock的monitor
            synchronized (lock){
                //当条件不满足时，继续wait，同时释放了lock的锁
                while (flag){
                    try {
                        System.out.println(Thread.currentThread()+"flag is true.wait@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }

                //条件满足时，完成工作
                System.out.println(Thread.currentThread()+"flag is false.running@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));

            }
        }
    }


    static class Notify implements Runnable{
        @Override
        public void run() {
            //加锁，拥有lock的monitor
            synchronized (lock){
                //获取lock的锁，然后进行通知，通知时不会释放lock的锁
                //知道当前线程释放了lock后，waitThread才能从wait方法中返回
                System.out.println(Thread.currentThread()+"hold lock.notify@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //再次加锁
            synchronized (lock){
                System.out.println(Thread.currentThread()+"hold lock again.sleep@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
